package com.xxx.demo.data.command;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.butid.data.NettyClient;
import com.github.butid.data.netty.springboot.SpringBootNettyProperties;
import com.xxx.demo.data.entity.TDevcmdrec;
import com.xxx.demo.data.entity.Wsunit;
import com.xxx.demo.data.service.TDevcmdrecService;
import com.xxx.demo.data.service.WsunitService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 命令下发控制器
 * @author wangjing.dc@qq.com
 * @since 2020/8/12
 */
@Slf4j
@Component
@EnableConfigurationProperties(SpringBootNettyProperties.class)
public class CommandPusher implements InitializingBean, DisposableBean {
    @Autowired
    private SpringBootNettyProperties bootNettyProperties;
    @Autowired
    private TDevcmdrecService cmdService;
    @Autowired
    private WsunitService wsunitService;

    // 任务下发线程池
    private ThreadPoolExecutor executor = new ThreadPoolExecutor(
            3, 5, 30, TimeUnit.SECONDS, new LinkedBlockingDeque<>());
    private boolean runStatu = true;

    // 命令下发扫描线程
    Thread thread = new Thread(()->{
        log.info("命令任务下发程已启动...");
        while(runStatu){
            List<TDevcmdrec> cmd = queryComandJob();
            if(cmd != null && cmd.size() > 0){
                cmd.forEach((item)->{
                    executor.execute(()->{
                        pushCommand(item);
                    });
                });
            }

            try {
                Thread.sleep(bootNettyProperties.getCommandPushTimer() * 1000);
            } catch (InterruptedException e) {
                log.error(null, e);
            }
        }

        log.info("命令任务下发线程已停止...");
    });

    /**
     * 查询需要推送的消息
     * @return
     */
    private List<TDevcmdrec> queryComandJob() {
        LambdaQueryWrapper<TDevcmdrec> query = new LambdaQueryWrapper<>();
        query.eq(TDevcmdrec::getCmdstate, "0")
                .orderByDesc(TDevcmdrec::getCreateTime);
        return cmdService.list(query);
    }

    /**
     * 推送消息
     *                  if ("1".equals(cmdstate)) cmdstate = "已发送命令";
     *             else if ("2".equals(cmdstate)) cmdstate = "正在执行";
     *             else if ("3".equals(cmdstate)) cmdstate = "成功";
     *             else if ("4".equals(cmdstate)) cmdstate = "失败";
     * @param cmd
     */
    private void pushCommand(TDevcmdrec cmd) {
        log.info("推送C端命令{}", cmd);

        try{
            // 状态更新为正在执行
            cmdService.updateById(cmd.setCmdstate(CmdConst.STATE_1));
            Wsunit unit = wsunitService.getByUntid(cmd.getUntid());
            NettyClient.send(unit.getNetaddr(), bootNettyProperties.getClientPort(), CommandBuilder.build(cmd), 60 * 1000);
//            NettyClient.sendUDP(unit.getNetaddr(), bootNettyProperties.getClientPort(), CommandBuilder.build(cmd));
        }catch (Exception e){
            log.error(null, e);
            log.info("推送C端命令出错{},msg:{}", e.getMessage(), cmd);
            cmdService.updateById(cmd.setCmdstate(CmdConst.STATE_4).setErrDetail(e.getMessage()));
        }
    }

    @Override
    public void destroy() throws Exception {
        runStatu = false;
        executor.shutdownNow();
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        executor.prestartAllCoreThreads();
        thread.start();
    }


}
